/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014, INDIAN INSTITUTE OF TECHNOLOGY, MADRAS
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Poornima Kalyan Sundaram <poornimaks93@gmail.com>
 */

#include "ns3/simulator.h"
#include "ns3/packet.h"
#include "ns3/pointer.h"
#include "ns3/double.h"
#include "ns3/uinteger.h"
#include "dca-txop.h"
#include "ns3/log.h"
#include "ns3/random-variable-stream.h"
#include "weighted-fair-queue.h"
#include "wifi-mac-queue.h"
#include "wifi-net-device.h"
#include "wifi-mac.h"
#include "qos-blocked-destinations.h"
#include "ns3/config-store-module.h"
#include "ns3/boolean.h"
#include "ns3/net-device-container.h"
#include "ns3/node-container.h"

namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (WeightedFairQueue);

TypeId WeightedFairQueue::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::WeightedFairQueue")
    .SetParent<Object> ()
    .AddConstructor<WeightedFairQueue> ()
    .AddAttribute ("maxFlows", "Maximum number of entries (per flow) that can be allowed in the hash table",
                   UintegerValue (10),
                   MakeUintegerAccessor (&WeightedFairQueue::m_maxFlows),
                   MakeUintegerChecker<uint32_t> ())
     .AddAttribute ("Mode", "Based on which all IP address the flows are classfied",
                   EnumValue (DESTINATION),
                   MakeEnumAccessor (&WeightedFairQueue::SetMode),
                   MakeEnumChecker (DESTINATION, "Destination",
									SOURCE, "Source",
                                    SOURCEDESTINATION, "SourceDestination"))
	
	;
  return tid;
}

WeightedFairQueue::WeightedFairQueue ()
{
}

WeightedFairQueue::~WeightedFairQueue ()
{
}

void
WeightedFairQueue::SetMode (WeightedFairQueue::mode mode1)
{
 
  m_mode = mode1;
}


void WeightedFairQueue::Install (NodeContainer d)
{
m_nodes=d;
for(uint16_t j=0;j<d.GetN();j++)
{
	Ptr<Node> node = d.Get(j); // Get station from node container 
	uint16_t n=node->GetNDevices();
	for(uint16_t k=0;k<n;k++)
	{
		 Ptr<NetDevice> dev = node->GetDevice(k);
		 Ptr<WifiNetDevice> wifi_dev = DynamicCast<WifiNetDevice>(dev);
		if(wifi_dev!=NULL)
		{
			 Ptr<WifiMac> mac = wifi_dev->GetMac();
			 PointerValue ptr;
			 mac->GetAttribute("DcaTxop", ptr);
			 Ptr<DcaTxop> dca = ptr.Get<DcaTxop>();
			 Ptr<WifiMacQueue> q=dca->GetQueue();
			 Ptr<WeightedFairQueue> pt=q->GetWfq();
			 q->SetAttribute("WeightedFairQueue",BooleanValue(true));
<<<<<<< HEAD
			 pt->m_mode=DESTINATION;
=======
			 pt->m_mode=DESTINATION;	
			 if(j<=0)
			 {
				 q->SetMaxSize(10);
				 q->SetAttribute("ap",UintegerValue(j));
			 }
				 else 
			 {
			 q->SetMaxSize(40);NS_LOG_UNCOND(j);
			 q->SetAttribute("ap",UintegerValue(j));
			  }
>>>>>>> afa53cfcfe4d60c8f0b358961c46125f02231ff4
		}
	}
}

}

void WeightedFairQueue::SetWeights(Ipv4Address address,double weights)
{
	
	//need the nodeset stored
	//edit the wifimacqueueA instance attributes of those nodesets

for(uint16_t j=0;j<m_nodes.GetN();j++)
{
	Ptr<Node> node = m_nodes.Get(j); // Get station from node container 
	uint32_t n=node->GetNDevices();
	for(uint16_t k=0;k<n;k++)
	{
		 Ptr<NetDevice> dev = node->GetDevice(k);

		 Ptr<WifiNetDevice> wifi_dev = DynamicCast<WifiNetDevice>(dev);
		if(wifi_dev!=NULL)
		{
			 Ptr<WifiMac> mac = wifi_dev->GetMac();
			 PointerValue ptr;
			 mac->GetAttribute("DcaTxop", ptr);
			 Ptr<DcaTxop> dca = ptr.Get<DcaTxop>();
			 Ptr<WifiMacQueue> q=dca->GetQueue();
			 Ptr<WeightedFairQueue> pt=q->GetWfq();
			 if(pt->m_mode==DESTINATION)
			 {
				if(pt->m_weightsTable.size()<m_maxFlows)
				pt->m_weightsTable.insert (std::make_pair(std::make_pair('\0',address),weights)); 
			}
			else
			{
				if(pt->m_weightsTable.size()<m_maxFlows)
				pt->m_weightsTable.insert (std::make_pair(std::make_pair(address,'\0'),weights)); 
			}
		}
	}
}

	
}

void WeightedFairQueue::SetWeights(Ipv4Address src_address,Ipv4Address dest_address,double weights)
{
	//if condition needed to check if the flow weights are already present!!
	//need the nodeset stored
	//edit the wifimacqueueA instance attributes of those nodesets

for(uint16_t j=0;j<m_nodes.GetN();j++)
{
	Ptr<Node> node = m_nodes.Get(j); // Get station from node container 
	uint16_t n=node->GetNDevices();

	for(uint16_t k=0;k<n;k++)
	{
		 Ptr<NetDevice> dev = node->GetDevice(k);
		 Ptr<WifiNetDevice> wifi_dev = DynamicCast<WifiNetDevice>(dev);
		if(wifi_dev!=NULL)
		{
			 Ptr<WifiMac> mac = wifi_dev->GetMac();
		     PointerValue ptr;
			 mac->GetAttribute("DcaTxop", ptr);
			 Ptr<DcaTxop> dca = ptr.Get<DcaTxop>();
			 Ptr<WifiMacQueue> q=dca->GetQueue();
			 Ptr<WeightedFairQueue> pt=q->GetWfq();
			 if(pt->m_weightsTable.size()<m_maxFlows)
			 pt->m_weightsTable.insert (std::make_pair(std::make_pair(src_address,dest_address),weights)); 
		}
	}
}

	
}


void WeightedFairQueue::Set(std::string name,std::string val)
{
	if(name=="Mode")
 {
	for(uint16_t j=0;j<m_nodes.GetN();j++)
  {
	Ptr<Node> node = m_nodes.Get(j); // Get station from node container 
	uint32_t n=node->GetNDevices();
	for(uint16_t k=0;k<n;k++)
	{
		 Ptr<NetDevice> dev = node->GetDevice(k);
		 Ptr<WifiNetDevice> wifi_dev = DynamicCast<WifiNetDevice>(dev);
		if(wifi_dev!=NULL)
		{
			       Ptr<WifiMac> mac = wifi_dev->GetMac();
				   PointerValue ptr;
			       mac->GetAttribute("DcaTxop", ptr);
				   Ptr<DcaTxop> dca = ptr.Get<DcaTxop>();
			       Ptr<WifiMacQueue> q=dca->GetQueue();
			       Ptr<WeightedFairQueue> pt=q->GetWfq();
				
						if(val=="Source")
						pt->m_mode=SOURCE;
						else if(val=="Destination")
						pt->m_mode=DESTINATION;
						else if(val=="SourceDestination")
						pt->m_mode=SOURCEDESTINATION;
				

	    	}
    	}
	}
 }

}

} // namespace ns3
